using Gma.System.MouseKeyHook;
using PInvoke;
using System.Diagnostics;

namespace ZTHelper
{
    public partial class MainForm : Form
    {
        private Process[] processes;
        private List<ProcessModel> processModels = new List<ProcessModel>();
        private CancellationTokenSource cancelTokenSource;
        private Task clickTask;
        private IKeyboardMouseEvents globalEvents = Hook.GlobalEvents();

        public MainForm()
        {
            InitializeComponent();
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            processes = Process.GetProcessesByName("Memu");
            foreach (var process in processes)
            {
                RECT rect = default;
                User32.GetWindowRect(process.MainWindowHandle, out rect);
                rect.left -= 8;
                rect.top -= 2;
                rect.right += 8;
                rect.bottom += 8;
                processModels.Add(new ProcessModel()
                {
                    Process = process,
                    Rect = rect,
                    Rectangle = new Rectangle(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top)
                });
                //Location = new Point(rect.left, rect.top);
                //Size = new Size(rect.right - rect.left, rect.bottom - rect.top);
            }

            globalEvents.KeyDown += (s, e) =>
            {
                if (e.KeyCode == Keys.T)
                {
                    button1_Click(null, null);
                }
                if (e.KeyCode == Keys.G)
                {
                    globalEvents.MouseClick -= MainForm_MouseClick;
                    globalEvents.MouseClick += MainForm_MouseClick;
                }
            };
            globalEvents.KeyUp += (s, e) =>
            {
                if (e.KeyCode == Keys.G)
                {
                    globalEvents.MouseClick -= MainForm_MouseClick;
                }
            };
        }

        private void MainForm_MouseClick(object sender, MouseEventArgs e)
        {
            if (clickTask != null)
            {
                return;
            }
            var pt = new Point(e.X, e.Y);
            var current = User32.GetForegroundWindow();
            var clickedProcess = processModels.FirstOrDefault(x => x.Rectangle.Contains(pt) && current == x.Process.MainWindowHandle);
            if (clickedProcess == null)
            {
                return;
            }
            var currentPt = User32.GetCursorPos();
            var clickedPoint = new Point(e.X - clickedProcess.Rect.left, e.Y - clickedProcess.Rect.top);
            var clickedPercentX = clickedPoint.X / (clickedProcess.Rectangle.Width * 1.0);
            var clickedPercentY = clickedPoint.Y / (clickedProcess.Rectangle.Height * 1.0);
            if (clickTask != null && clickTask.Status == TaskStatus.Running)
            {
                cancelTokenSource.Cancel();
                cancelTokenSource = new CancellationTokenSource();
            }
            else
            {
                cancelTokenSource = new CancellationTokenSource();
            }

            clickTask = Task.Delay(500, cancelTokenSource.Token).ContinueWith(t =>
            {
                if (t.IsCanceled)
                {
                    return;
                }

                Invoke(() =>
                {
                    foreach (var item in processModels)
                    {
                        if (item == clickedProcess)
                        {
                            continue;
                        }
                        int x = (int)(item.Width * clickedPercentX + item.Rect.left);
                        int y = (int)(item.Height * clickedPercentY + item.Rect.top + 15);
                        User32.SetCursorPos(x, y);
                        User32.SetForegroundWindow(item.Process.MainWindowHandle);
                        Thread.Sleep(50);
                        User32.mouse_event(User32.mouse_eventFlags.MOUSEEVENTF_LEFTDOWN | User32.mouse_eventFlags.MOUSEEVENTF_LEFTUP | User32.mouse_eventFlags.MOUSEEVENTF_ABSOLUTE, x, y, 0, 0);
                    }

                    clickTask = null;
                    User32.SetCursorPos(currentPt.x, currentPt.y);
                    User32.SetForegroundWindow(current);
                });
            });
        }

        private void button1_Click(object sender, EventArgs e)
        {
            var pt = User32.GetCursorPos();
            var current = User32.GetForegroundWindow();
            foreach (var item in processModels)
            {
                int x = (int)(item.Width * 0.08 + item.Rect.left);
                int y = (int)(item.Height * 0.3 + item.Rect.top);
                User32.SetCursorPos(x, y);
                User32.SetForegroundWindow(item.Process.MainWindowHandle);
                User32.mouse_event(User32.mouse_eventFlags.MOUSEEVENTF_LEFTDOWN | User32.mouse_eventFlags.MOUSEEVENTF_LEFTUP | User32.mouse_eventFlags.MOUSEEVENTF_ABSOLUTE, x, y, 0, 0);
                Thread.Sleep(100);
                User32.mouse_event(User32.mouse_eventFlags.MOUSEEVENTF_LEFTDOWN | User32.mouse_eventFlags.MOUSEEVENTF_LEFTUP | User32.mouse_eventFlags.MOUSEEVENTF_ABSOLUTE, x, y, 0, 0);
                Thread.Sleep(100);

            }
            User32.SetCursorPos(pt.x, pt.y);
            User32.SetForegroundWindow(current);
        }

        private static void SendAttach(ProcessModel item)
        {
            int y = (int)(item.Height * 0.54 + item.Rect.top);
            int x = (int)(item.Width * 0.64 + item.Rect.left);
            User32.SetCursorPos(x, y);
            User32.SetForegroundWindow(item.Process.MainWindowHandle);
            User32.mouse_event(User32.mouse_eventFlags.MOUSEEVENTF_LEFTDOWN | User32.mouse_eventFlags.MOUSEEVENTF_LEFTUP | User32.mouse_eventFlags.MOUSEEVENTF_ABSOLUTE, x, y, 0, 0);
            Thread.Sleep(10);
        }
    }
    public class ProcessModel
    {
        public Process Process { get; set; }

        public RECT Rect { get; set; }

        public Rectangle Rectangle { get; set; }

        public int Width => Rect.right - Rect.left;

        public int Height => Rect.bottom - Rect.top;
    }
}
